1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55 package java.lang;
56
57 import java.io.*;
58 import java.util.*;
59
60
61 final class ProcessEnvironment
62 {
63 private static final HashMap<Variable,Value> theEnvironment;
64 private static final Map<String,String> theUnmodifiableEnvironment;
65 static final int MIN_NAME_LENGTH = 0;
66
67 static {
68
69
70 byte[][] environ = environ();
71 theEnvironment = new HashMap<>(environ.length/2 + 3);
72
73
74 for (int i = environ.length-1; i > 0; i-=2)
75 theEnvironment.put(Variable.valueOf(environ[i-1]),
76 Value.valueOf(environ[i]));
77
78 theUnmodifiableEnvironment
79 = Collections.unmodifiableMap
80 (new StringEnvironment(theEnvironment));
81 }
82
83
84 static String getenv(String name) {
85 return theUnmodifiableEnvironment.get(name);
86 }
87
88
89 static Map<String,String> getenv() {
90 return theUnmodifiableEnvironment;
91 }
92
93
94 static Map<String,String> environment() {
95 return new StringEnvironment
96 ((Map<Variable,Value>)(theEnvironment.clone()));
97 }
98
99
100 static Map<String,String> emptyEnvironment(int capacity) {
101 return new StringEnvironment(new HashMap<Variable,Value>(capacity));
102 }
103
104 private static native byte[][] environ();
105
106
107 private ProcessEnvironment() {}
108
109
110 private static void validateVariable(String name) {
111 if (name.indexOf('=') != -1 ||
112 name.indexOf('\u0000') != -1)
113 throw new IllegalArgumentException
114 ("Invalid environment variable name: \"" + name + "\"");
115 }
116
117
118 private static void validateValue(String value) {
119 if (value.indexOf('\u0000') != -1)
120 throw new IllegalArgumentException
121 ("Invalid environment variable value: \"" + value + "\"");
122 }
123
124
125
126 private static abstract class ExternalData {
127 protected final String str;
128 protected final byte[] bytes;
129
130 protected ExternalData(String str, byte[] bytes) {
131 this.str = str;
132 this.bytes = bytes;
133 }
134
135 public byte[] getBytes() {
136 return bytes;
137 }
138
139 public String toString() {
140 return str;
141 }
142
143 public boolean equals(Object o) {
144 return o instanceof ExternalData
145 && arrayEquals(getBytes(), ((ExternalData) o).getBytes());
146 }
147
148 public int hashCode() {
149 return arrayHash(getBytes());
150 }
151 }
152
153 private static class Variable
154 extends ExternalData implements Comparable<Variable>
155 {
156 protected Variable(String str, byte[] bytes) {
157 super(str, bytes);
158 }
159
160 public static Variable valueOfQueryOnly(Object str) {
161 return valueOfQueryOnly((String) str);
162 }
163
164 public static Variable valueOfQueryOnly(String str) {
165 return new Variable(str, str.getBytes());
166 }
167
168 public static Variable valueOf(String str) {
169 validateVariable(str);
170 return valueOfQueryOnly(str);
171 }
172
173 public static Variable valueOf(byte[] bytes) {
174 return new Variable(new String(bytes), bytes);
175 }
176
177 public int compareTo(Variable variable) {
178 return arrayCompare(getBytes(), variable.getBytes());
179 }
180
181 public boolean equals(Object o) {
182 return o instanceof Variable && super.equals(o);
183 }
184 }
185
186 private static class Value
187 extends ExternalData implements Comparable<Value>
188 {
189 protected Value(String str, byte[] bytes) {
190 super(str, bytes);
191 }
192
193 public static Value valueOfQueryOnly(Object str) {
194 return valueOfQueryOnly((String) str);
195 }
196
197 public static Value valueOfQueryOnly(String str) {
198 return new Value(str, str.getBytes());
199 }
200
201 public static Value valueOf(String str) {
202 validateValue(str);
203 return valueOfQueryOnly(str);
204 }
205
206 public static Value valueOf(byte[] bytes) {
207 return new Value(new String(bytes), bytes);
208 }
209
210 public int compareTo(Value value) {
211 return arrayCompare(getBytes(), value.getBytes());
212 }
213
214 public boolean equals(Object o) {
215 return o instanceof Value && super.equals(o);
216 }
217 }
218
219
220 private static class StringEnvironment
221 extends AbstractMap<String,String>
222 {
223 private Map<Variable,Value> m;
224 private static String toString(Value v) {
225 return v == null ? null : v.toString();
226 }
227 public StringEnvironment(Map<Variable,Value> m) {this.m = m;}
228 public int size() {return m.size();}
229 public boolean isEmpty() {return m.isEmpty();}
230 public void clear() { m.clear();}
231 public boolean containsKey(Object key) {
232 return m.containsKey(Variable.valueOfQueryOnly(key));
233 }
234 public boolean containsValue(Object value) {
235 return m.containsValue(Value.valueOfQueryOnly(value));
236 }
237 public String get(Object key) {
238 return toString(m.get(Variable.valueOfQueryOnly(key)));
239 }
240 public String put(String key, String value) {
241 return toString(m.put(Variable.valueOf(key),
242 Value.valueOf(value)));
243 }
244 public String remove(Object key) {
245 return toString(m.remove(Variable.valueOfQueryOnly(key)));
246 }
247 public Set<String> keySet() {
248 return new StringKeySet(m.keySet());
249 }
250 public Set<Map.Entry<String,String>> entrySet() {
251 return new StringEntrySet(m.entrySet());
252 }
253 public Collection<String> values() {
254 return new StringValues(m.values());
255 }
256
257
258
259
260
261
262
263
264
265
266
267
268
269 public byte[] toEnvironmentBlock(int[]envc) {
270 int count = m.size() * 2;
271 for (Map.Entry<Variable,Value> entry : m.entrySet()) {
272 count += entry.getKey().getBytes().length;
273 count += entry.getValue().getBytes().length;
274 }
275
276 byte[] block = new byte[count];
277
278 int i = 0;
279 for (Map.Entry<Variable,Value> entry : m.entrySet()) {
280 byte[] key = entry.getKey ().getBytes();
281 byte[] value = entry.getValue().getBytes();
282 System.arraycopy(key, 0, block, i, key.length);
283 i+=key.length;
284 block[i++] = (byte) '=';
285 System.arraycopy(value, 0, block, i, value.length);
286 i+=value.length + 1;
287
288
289 }
290 envc[0] = m.size();
291 return block;
292 }
293 }
294
295 static byte[] toEnvironmentBlock(Map<String,String> map, int[]envc) {
296 return map == null ? null :
297 ((StringEnvironment)map).toEnvironmentBlock(envc);
298 }
299
300
301 private static class StringEntry
302 implements Map.Entry<String,String>
303 {
304 private final Map.Entry<Variable,Value> e;
305 public StringEntry(Map.Entry<Variable,Value> e) {this.e = e;}
306 public String getKey() {return e.getKey().toString();}
307 public String getValue() {return e.getValue().toString();}
308 public String setValue(String newValue) {
309 return e.setValue(Value.valueOf(newValue)).toString();
310 }
311 public String toString() {return getKey() + "=" + getValue();}
312 public boolean equals(Object o) {
313 return o instanceof StringEntry
314 && e.equals(((StringEntry)o).e);
315 }
316 public int hashCode() {return e.hashCode();}
317 }
318
319 private static class StringEntrySet
320 extends AbstractSet<Map.Entry<String,String>>
321 {
322 private final Set<Map.Entry<Variable,Value>> s;
323 public StringEntrySet(Set<Map.Entry<Variable,Value>> s) {this.s = s;}
324 public int size() {return s.size();}
325 public boolean isEmpty() {return s.isEmpty();}
326 public void clear() { s.clear();}
327 public Iterator<Map.Entry<String,String>> iterator() {
328 return new Iterator<Map.Entry<String,String>>() {
329 Iterator<Map.Entry<Variable,Value>> i = s.iterator();
330 public boolean hasNext() {return i.hasNext();}
331 public Map.Entry<String,String> next() {
332 return new StringEntry(i.next());
333 }
334 public void remove() {i.remove();}
335 };
336 }
337 private static Map.Entry<Variable,Value> vvEntry(final Object o) {
338 if (o instanceof StringEntry)
339 return ((StringEntry)o).e;
340 return new Map.Entry<Variable,Value>() {
341 public Variable getKey() {
342 return Variable.valueOfQueryOnly(((Map.Entry)o).getKey());
343 }
344 public Value getValue() {
345 return Value.valueOfQueryOnly(((Map.Entry)o).getValue());
346 }
347 public Value setValue(Value value) {
348 throw new UnsupportedOperationException();
349 }
350 };
351 }
352 public boolean contains(Object o) { return s.contains(vvEntry(o)); }
353 public boolean remove(Object o) { return s.remove(vvEntry(o)); }
354 public boolean equals(Object o) {
355 return o instanceof StringEntrySet
356 && s.equals(((StringEntrySet) o).s);
357 }
358 public int hashCode() {return s.hashCode();}
359 }
360
361 private static class StringValues
362 extends AbstractCollection<String>
363 {
364 private final Collection<Value> c;
365 public StringValues(Collection<Value> c) {this.c = c;}
366 public int size() {return c.size();}
367 public boolean isEmpty() {return c.isEmpty();}
368 public void clear() { c.clear();}
369 public Iterator<String> iterator() {
370 return new Iterator<String>() {
371 Iterator<Value> i = c.iterator();
372 public boolean hasNext() {return i.hasNext();}
373 public String next() {return i.next().toString();}
374 public void remove() {i.remove();}
375 };
376 }
377 public boolean contains(Object o) {
378 return c.contains(Value.valueOfQueryOnly(o));
379 }
380 public boolean remove(Object o) {
381 return c.remove(Value.valueOfQueryOnly(o));
382 }
383 public boolean equals(Object o) {
384 return o instanceof StringValues
385 && c.equals(((StringValues)o).c);
386 }
387 public int hashCode() {return c.hashCode();}
388 }
389
390 private static class StringKeySet extends AbstractSet<String> {
391 private final Set<Variable> s;
392 public StringKeySet(Set<Variable> s) {this.s = s;}
393 public int size() {return s.size();}
394 public boolean isEmpty() {return s.isEmpty();}
395 public void clear() { s.clear();}
396 public Iterator<String> iterator() {
397 return new Iterator<String>() {
398 Iterator<Variable> i = s.iterator();
399 public boolean hasNext() {return i.hasNext();}
400 public String next() {return i.next().toString();}
401 public void remove() { i.remove();}
402 };
403 }
404 public boolean contains(Object o) {
405 return s.contains(Variable.valueOfQueryOnly(o));
406 }
407 public boolean remove(Object o) {
408 return s.remove(Variable.valueOfQueryOnly(o));
409 }
410 }
411
412
413 private static int arrayCompare(byte[]x, byte[] y) {
414 int min = x.length < y.length ? x.length : y.length;
415 for (int i = 0; i < min; i++)
416 if (x[i] != y[i])
417 return x[i] - y[i];
418 return x.length - y.length;
419 }
420
421
422 private static boolean arrayEquals(byte[] x, byte[] y) {
423 if (x.length != y.length)
424 return false;
425 for (int i = 0; i < x.length; i++)
426 if (x[i] != y[i])
427 return false;
428 return true;
429 }
430
431
432 private static int arrayHash(byte[] x) {
433 int hash = 0;
434 for (int i = 0; i < x.length; i++)
435 hash = 31 * hash + x[i];
436 return hash;
437 }
438
439 }